<?php

namespace Model;

class Users extends \Zend_Db_Table_Abstract
{
    /**
     * @var string
     */
    protected $_name            = 'users';
    /**
     * @var usersProfile
     */
    protected $mUsersProfile     = NULL;
    
    /**
     * @param array $config optional
     */
    public function __construct($config = array())
    {
        parent::__construct($config);
        
        $this->mUsersProfile = new \Model\usersProfile($config);
    }
    
    /**
     * Is user (id) exists?
     * 
     * @param int $userId
     * @return bool
     */
    public function existsUserId($userId)
    {
        $stmt = $this->getAdapter()->query(
        "SELECT COUNT(*) AS count
                FROM {$this->_name}
                WHERE id = ?",
        array($userId));

        $row = $stmt->fetch();
        
        return (bool)$row['count'];
    }
    
    /**
     * Is user (email) exists?
     * 
     * @param string $email
     * @return bool
     */
    public function existsUserEmail($email)
    {
        $stmt = $this->getAdapter()->query(
        "SELECT COUNT(*) AS count
                FROM {$this->_name}
                WHERE email = ?",
        array($email));

        $row = $stmt->fetch();
        
        return (bool)$row['count'];
    }
    
    /**
     * Is username exists?
     * 
     * @param string $userName
     * @return bool
     */
    public function existsUserUserName($userName)
    {
        $stmt = $this->getAdapter()->query(
        "SELECT COUNT(*) AS count
                FROM {$this->_name}
                WHERE userName = ?",
        array($userName));

        $row = $stmt->fetch();
        
        return (bool)$row['count'];
    }
    
    /**
     * @param array $input email, password, name
     * @return int
     */
    public function insertUser(array $input)
    {   
        \Helper\array_isset($input, array('email','userName','password','name'));
        
        $stmt = $this->getAdapter()->query(
        "INSERT INTO {$this->_name} SET
                email = ?,
                userName = ?,
                password = ?,
                active = 0;",
        array(  $input['email'], $input['userName'],
                \sha1($input['password'].\ZReg::get('config')->crypt->salt)));
            
        $lId = $stmt->getDriverStatement()->insert_id;
        if ($lId)
        {
            $this->mUsersProfile->insertUserProfile($lId, $input);
        }
       
        return $lId;
    }
    
    /**
     * @param array $input email, password, name
     * @return array
     */
    public function ctrlInsertUser(array $input)
    {
        \Helper\array_isset($input, array('email','userName','password','name'));
        
        $res = array('ret' => NULL, 'err' => array());
        
        if ($this->existsUserEmail($input['email']))
            $res['err'][] = \ZReg::get('i18n')->get('errEmailExists');
        if ($this->existsUserUserName($input['userName']))
            $res['err'][] = \ZReg::get('i18n')->get('errUserNameExists');
        
        if (empty($res['err']))
        $res['ret'] = $this->insertUser($input);
        
        return $res;
    }
    
    /**
     * Get a user
     * 
     * @param array $select
     * @param string $whereColumn
     * @param mixed $whereValue
     * @return mixed if no row then false
     */
    public function getUser(array $select, $whereColumn, $whereValue)
    {
        $selectQuery = implode(',', $select);
        
        $stmt = $this->getAdapter()->query(
        "SELECT {$selectQuery}
                FROM {$this->_name}
                WHERE `{$whereColumn}` = ?
                LIMIT 1;",
        array($whereValue));
        
        return $stmt->fetch();
    }
    
    /**
     * @param int $userId
     * @param array $input column => value
     * @return int
     */
    public function updateUser($userId, array $input)
    {   
        $setQuery = implode(' = ?,', array_keys($input)).' = ?';
        
        $stmt = $this->getAdapter()->query(
        "UPDATE {$this->_name} SET
                {$setQuery}
                WHERE id = ?;",
        array_values(array_merge($input, array($userId))));
                
        return $stmt->getDriverStatement()->affected_rows;
    }
    
    /**
     * @param int $userId no check for existing
     * @param array $input email, name
     * @return int
     */
    public function ctrlSendRegistrationEmail($userId, array $input)
    {        
        \Helper\array_isset($input, array('email','name'));
        
        // create activation code
        $code = \sha1($input['email'].\ZReg::get('config')->crypt->salt);
        // create activation link
        $link = \ZReg::get('serPaths')->baseUrl.
                "auth/activate-registration/".
                "id/".base64_encode($userId)."/code/{$code}";
        // create message body
        $params = array('%name' => $input['name'], 
                        '%link' => $link);
        $body   = str_replace(  '\n',
                                '<br />',
                                \ZReg::get('i18n')->
                                    get('emailRegistrationBody', $params));
        // create message
        $message = \Swift_Message::newInstance()
            ->setSubject(\ZReg::get('i18n')->get('emailRegistrationSubject'))
            ->setFrom(array(\ZReg::get('config')->mailer->from->email
                            =>
                            \ZReg::get('config')->mailer->from->name))
            ->setTo($input['email'])
            ->addPart($body, 'text/html');
        // send message
        $result = \ZReg::get('mailer')->send($message);
        
        return $result;
    }

    /**
     * @param int $userId
     * @param string $code 
     */
    public function ctrlActivateUser($userId, $code)
    {
        if ( ! $this->existsUserId($userId))
            throw new \DomainException("\$userId = {$userId} doesnt exists!");
        
        $user       = $this->getUser(array('email'), 'id', $userId);
        $userCode   = \sha1($user['email'].
                            \ZReg::get('config')->crypt->salt);
        if ($userCode !== $code)
            throw new \InvalidArgumentException("\$code = {$code} is wrong!");
        // everything is ok
        $result = $this->updateUser($userId, array('active' => 1));
        
        if ( ! $result)
            throw new \LogicException('Already activated user?');
    }
    
    /**
     * @param array $input email, password
     * @return int
     */
    public function loginUser($input)
    {
        \Helper\array_isset($input, array('email','password'));
        
        // get user
        $user = $this->getUser( array('id','password','active'),
                                'email', $input['email']);
        if ( ! $user)
            throw new \DomainException("email = {$input['email']} doesnt exists!}");
        elseif ( ! $user['active'])
            throw new \DomainException("email = {$input['email']} doesnt activated!}");
        // check: sha1(password.salt)
        $password = \sha1($input['password'].\ZReg::get('config')->crypt->salt);
        if ($user['password'] !== $password)
            throw new \DomainException('Password is wrong!');
        
        return $user['id'];
    }
    
    /**
     * @param array $input email, password
     * @return array
     */
    public function ctrlLoginUser($input)
    {
        $res = array('ret' => NULL, 'err' => array());
        
        try
        {
            $res['ret'] = $this->loginUser($input);
            
            
            if ( ! \Zend_Session::isStarted())
            {
                \Zend_Session::start();
                \Zend_Session::setOptions(\ZReg::get('config')->session->toArray());
            }
            
            $sessionUser    = new \Zend_Session_Namespace('user');
            $extraTokenName = \ZReg::get('config')->sessionExtra->tokenName;
            $extraToken     = \uniqid();
            // set extra token both server/client side
            $sessionUser->{$extraTokenName} = $extraToken;
            \setcookie( $extraTokenName,
                        $extraToken,
                        0,
                        '/',
                        '',//\ZReg::get('serPaths')->name,
                        \ZReg::get('serPaths')->https,
                        TRUE);
            
            // set user datas (id, username, name)
            $userDatas = 
                $this->getUser(array('userName'), 'id', $res['ret']);
            $userProfileDatas =
                $this->mUsersProfile->getUserProfile($res['ret'], array('name'));
            
            $sessionUser->id        = $res['ret'];
            $sessionUser->userName  = $userDatas['userName'];
            $sessionUser->name      = $userProfileDatas['name'];
        }
        catch (\DomainException $e)
        {
            $res['err'][] = \ZReg::get('i18n')->get('errLogin');
        }
        
        return $res;
    }
    
    /**
     * 
     */
    public function ctrlLogoutUser()
    {
        if ( ! \Zend_Session::isStarted())
            throw new \DomainException('Theres no started session!');
        
        \Zend_Session::destroy();
        $extraTokenName = \ZReg::get('config')->sessionExtra->tokenName;
        \setcookie( $extraTokenName,
                    NULL,
                    time()-3600,
                    '/',
                    '',//\ZReg::get('serPaths')->name,
                    \ZReg::get('serPaths')->https,
                    TRUE);
    }
}

# eof